package handlers;

import dao.DataAccess;
import model.Address;
import model.Person;
import model.PhoneNumber;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Stateless(name = "PersonServiceHandler")
public class PersonServiceHandlerBean implements PersonServiceHandler {

    private DataAccess dataAccess;

    @EJB(beanName = "DataAccess")
    public void setDataAccess(DataAccess dataAccess) {
        this.dataAccess = dataAccess;
    }

    @Override
    public Person addPerson(Person person) {
        return dataAccess.add(person);
    }

    @Override
    public Person findPerson(Long id) {
        return dataAccess.find(Person.class, id);
    }

    @Override
    public Person alterPerson(Person person) {
        return dataAccess.alter(person);
    }

    @Override
    public void removePerson(Long id) {
        dataAccess.remove(Person.class, id);
    }

    @Override
    public Address addAddress(Address address) {
        List<Address> result = findAddressByInfo(address);

        if (result.size() > 0) {
            return result.get(0);
        } else {
            return dataAccess.add(address);
        }
    }

    @Override
    public Address findAddress(Long id) {
        return dataAccess.find(Address.class, id);
    }

    @Override
    public List<Address> findAddressByInfo(Address address) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("city", address.getCity());
        params.put("street", address.getStreet());
        params.put("building", address.getBuilding());
        params.put("apartment", address.getApartment());
        return dataAccess.findByCriteria(Address.class, params);
    }

    @Override
    public Address alterAddress(Address address) {
        return dataAccess.alter(address);
    }

    @Override
    public void removeAddress(Long id) {
        dataAccess.remove(Address.class, id);
    }

    @Override
    public PhoneNumber addPhoneNumber(PhoneNumber phoneNumber, Person person) {
        phoneNumber.setPerson(person);
        return dataAccess.add(phoneNumber);
    }

    @Override
    public PhoneNumber findPhoneNumber(Long id) {
        return dataAccess.find(PhoneNumber.class, id);
    }

    @Override
    public PhoneNumber alterPhoneNumber(PhoneNumber phoneNumber) {
        return dataAccess.alter(phoneNumber);
    }

    @Override
    public void removePhoneNumber(Long id) {
        dataAccess.remove(PhoneNumber.class, id);
    }

    @Override
    public List<Person> getAllPersons() {
        return dataAccess.findAll(Person.class);
    }

    @Override
    public List<Address> getAllAddresses() {
        return dataAccess.findAll(Address.class);
    }

    @Override
    public List<PhoneNumber> getAllPhoneNumbers() {
        return dataAccess.findAll(PhoneNumber.class);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public Person addCompletePerson(Person person, List<Address> addresses, List<PhoneNumber> phoneNumbers) {
        person = dataAccess.add(person);

        for (Address address : addresses) {
            address = addAddress(address);
            linkAddress(person, address);
        }

        for (PhoneNumber number : phoneNumbers) {
            addPhoneNumber(number, person);
        }

        return person;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void linkAddress(Person person, Address address) {
        person.getAddresses().add(address);
        address.getPersons().add(person);
        dataAccess.alter(person);
        dataAccess.alter(address);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void detachAddress(Person person, Address address) {
        person.getAddresses().remove(address);
        address.getPersons().remove(person);
        dataAccess.alter(person);

        if (isOrphanAddress(address)) {
            removeAddress(address.getId());
        } else {
            dataAccess.alter(address);
        }
    }

    @Override
    public boolean ensureUniqueMail(String mail) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("description", mail);
        List<Person> persons = dataAccess.findByCriteria(Person.class, params);

        if (persons.size() > 1) {
            throw new IllegalStateException("Persons with equal mails found");
        }
        return persons.size() < 1;
    }

    @Override
    public boolean ensureUniquePhone(PhoneNumber phoneNumber) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("code", phoneNumber.getCode());
        params.put("number", phoneNumber.getNumber());
        List<PhoneNumber> numbers = dataAccess.findByCriteria(PhoneNumber.class, params);

        if (numbers.size() > 1) {
            throw new IllegalStateException("Equal phone numbers found");
        }
        return numbers.size() < 1;
    }

    @Override
    public boolean isOrphanAddress(Address address) {
        return address.getPersons().size() < 1;
    }

}























